package com.sdy.healthcode.h5.controller.user;

import com.sdy.common.model.BizException;
import com.sdy.common.model.FileObj;
import com.sdy.common.model.Response;
import com.sdy.common.model.Result;
import com.sdy.common.utils.Assert;
import com.sdy.common.utils.StringUtil;
import com.sdy.healthcode.biz.constants.RedisConstants;
import com.sdy.healthcode.biz.dto.UserApplyPost;
import com.sdy.healthcode.biz.model.ApplyPost;
import com.sdy.healthcode.biz.model.HealthCode;
import com.sdy.healthcode.biz.model.User;
import com.sdy.healthcode.biz.service.ApplyPostService;
import com.sdy.healthcode.biz.service.ExpertsAppointmentService;
import com.sdy.healthcode.biz.service.HealthCodeService;
import com.sdy.healthcode.biz.service.UserService;
import com.sdy.healthcode.biz.utils.HttpReqUtil;
import com.sdy.healthcode.h5.vo.HealthCodeVO;
import com.sdy.healthcode.h5.vo.IdCardOcrObj;
import com.sdy.healthcode.h5.config.AppConfig;
import com.sdy.mvc.controller.BaseController;
import com.sdy.mvc.utils.JsonUtil;
import com.sdy.redis.service.RedisService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.httpclient.methods.multipart.FilePart;
import org.apache.commons.httpclient.methods.multipart.Part;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.FileSystemResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.UUID;

@Slf4j
@Controller
@RequestMapping("/healthcode")
@Api(tags = "用户健康码相关接口")
public class HealthCodeController extends BaseController {
    @Autowired
    private HealthCodeService healthCodeService;
    @Autowired
    private AppConfig appConfig;
    @Autowired
    private UserService userService;
    @Autowired
    private ApplyPostService applyPostService;
    @Autowired
    private RedisService redisService;
    @Autowired
    private ExpertsAppointmentService expertsAppointmentService;

    /**
     * 上次申请单数据
     */
    @GetMapping("/lastApplyInfo")
    @ResponseBody
    @ApiOperation(value = "上次申请单数据")
    public Response lastApplyInfo(HttpServletRequest request) {
        Integer userId = getUserId(request);
        ApplyPost ap = applyPostService.queryApplyPost(userId);
        UserApplyPost uap = UserApplyPost.from(ap);
        return Response.success(uap);
    }

    /**
     * 健康码申请
     * @param userApplyPost 申请表单数据
     */
    @PostMapping("/apply")
    @ResponseBody
    @ApiOperation(value = "健康码申请")
    public Response apply(HttpServletRequest request, @RequestBody UserApplyPost userApplyPost) throws BizException {
        if (userApplyPost == null) {
            return Response.error("申请表单不能为空。");
        }
        Integer applyUserId = getUserId(request);
        userApplyPost.setApplyUserId(applyUserId);
        if (userApplyPost.getUserId() == null) {
            userApplyPost.setUserId(applyUserId);
        }
        Result<String> r = healthCodeService.applyForCodeLockable(userApplyPost, appConfig.getDomain());
        if (!r.getSuccess()) {
            return Response.error(r.getMessage());
        }
        return Response.success();
    }
    
    @GetMapping("/profile")
    @ResponseBody
    @ApiOperation(value = "用户健康码数据", notes = "不存在健康码则data为null")
    public Response<HealthCodeVO> profile(HttpServletRequest request) throws BizException {
        Integer userId = getUserId(request);
        HealthCode healthCode = healthCodeService.queryHealthCode(userId);
        if (healthCode == null) {
            return Response.success();
        }
        User user = userService.getById(userId);
        ApplyPost applyPost = applyPostService.queryApplyPost(user.getId());
        HealthCodeVO vo = new HealthCodeVO()
                .setName(user.getName())
                .setHcode(healthCode.getHcode())
                .setType(healthCode.getType())
                .setUpdateTime(healthCode.getUpdateTime())
                .setAppointmentTime(applyPost == null ? null : applyPost.getAppointmentTime())
                .setQrcodePath("/healthcode/qrcode?_ts=" + healthCode.getId());
        if (healthCode.getType().equals(1)) {
            // TODO
            vo.setExpertsAppointment(expertsAppointmentService.getExpertInfo(userId));
        }
        return Response.success(vo);
    }
    
    @GetMapping("/qrcode")
    @ApiOperation(value = "当前用户健康二维码")
    public ResponseEntity<FileSystemResource> qrcode(HttpServletRequest request) throws Exception {
        HealthCode healthCode = healthCodeService.queryHealthCode(getUserId(request));
        if (healthCode == null) {
            return null;
        }
        File file = getFileByDir(healthCode.getQrcodePath());
        if (file == null) {
            return null;
        }
        if (!file.exists()) {
            healthCodeService.reGenerateHealthQrCode(healthCode, appConfig.getDomain());
        }
        MediaType contentType;
        HttpHeaders headers = new HttpHeaders();
        if (file.getName().endsWith(".png")) {
            contentType = MediaType.IMAGE_PNG;
        } else if (file.getName().endsWith(".jpg")) {
            contentType = MediaType.IMAGE_JPEG;
        } else if (file.getName().endsWith(".gif")) {
            contentType = MediaType.IMAGE_GIF;
        } else {
            contentType = MediaType.APPLICATION_OCTET_STREAM;
            headers.add("Cache-Control", "no-cache, no-store, must-revalidate");
            headers.add("Content-Disposition", "attachment; filename="
                    + URLEncoder.encode(file.getName(), "UTF-8").replace("+", " "));
        }
        headers.add("Pragma", "no-cache");
        headers.add("Expires", "0");
        headers.add("Last-Modified", new Date().toString());
        headers.add("ETag", String.valueOf(System.currentTimeMillis()));

        return ResponseEntity.ok().headers(headers)
                .contentLength(file.length())
                .contentType(contentType)
                .body(new FileSystemResource(file));
    }

    @GetMapping("/parseIdCard")
    @ResponseBody
    @ApiOperation(value = "身份证识别")
    @ApiImplicitParam(value = "文件ID", name = "fileId")
    public Response<IdCardOcrObj> parseIdCard(String fileId) throws Exception {
        FileObj fileObj = redisService.get(RedisConstants.FILE_UPLOAD_UUID + fileId, FileObj.class);
        Assert.isNull(fileObj, "上传的文件已过期，请重新上传。");
        File f = new File(fileObj.getPath());
        FilePart fp = new FilePart("image_file", f);
        Part[] parts = {fp};
        String jsonStr = HttpReqUtil.postMultipart(
                "http://trial.web.glority.cn:8000/classify?type=8",
                parts,
                StandardCharsets.UTF_8.name(),
                StandardCharsets.UTF_8.name(),
                3000, null);
        IdCardOcrObj result = JsonUtil.fromJson(jsonStr, IdCardOcrObj.class);
        return Response.success(result);
    }

    private File getFileByDir(String filedir) {
        if (StringUtil.isBlank(filedir)) {
            return null;
        }
        if (filedir.contains("..")) {
            return null;
        }
        return new File(filedir);
    }
}
